﻿using AutoMapper;
using DTcms.Core.Common.Emum;
using DTcms.Core.Common.Extensions;
using DTcms.Core.Common.Helper;
using DTcms.Core.DBFactory.Database;
using DTcms.Core.IServices;
using DTcms.Core.Model.Models;
using DTcms.Core.Model.ViewModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace DTcms.Core.Services
{
    /// <summary>
    /// 站点
    /// 继承于父类，拥有共同的方法
    /// </summary>
    public class SiteService : BaseService, ISiteService
    {
        private readonly IUserService _userService;
        private readonly IMapper _mapper;
        public SiteService(IDbContextFactory contentFactory,
            IUserService userService, IMapper mapper) : base(contentFactory)
        {
            _userService = userService;
            _mapper = mapper;
        }

        /// <summary>
        /// 查询默认站点信息
        /// </summary>
        public async Task<Sites> QueryDefaultAsync(WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            return await _context.Set<Sites>().FirstOrDefaultAsync(x => x.IsDefault > 0);
        }

        /// <summary>
        /// 根据域名查询站点信息
        /// </summary>
        public async Task<Sites> QueryByDomainAsync(string domain, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            SiteDomain result = await _context.Set<SiteDomain>()
                .Include(d => d.Site)
                .FirstOrDefaultAsync(x => x.Domain.ToLower() == domain.ToLower());
            return result != null ? result.Site : null;
        }

        /// <summary>
        /// 获取站点信息(带域名)
        /// </summary>
        public async Task<Sites> QueryAsync(Expression<Func<Sites, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            Sites result = await _context.Set<Sites>()
                .Include(d => d.SiteDomains)
                .FirstOrDefaultAsync(funcWhere);
            return result;
        }

        /// <summary>
        /// 获取站点列表(带域名)
        /// </summary>
        public async Task<IEnumerable<Sites>> QueryListAsync(int top, Expression<Func<Sites, bool>> funcWhere, string orderBy,
            WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            var result = _context.Set<Sites>().Include(x => x.SiteDomains).Where(funcWhere);//条件筛选
            result = LinqExtensions.OrderByBatch(result, orderBy);//调用Linq扩展类进行排序
            if (top > 0) result = result.Take(top);//等于0显示所有数据
            return await result.ToListAsync();
        }

        /// <summary>
        /// 获取站点分页列表(带域名)
        /// </summary>
        public async Task<PaginationList<Sites>> QueryPageAsync(int pageSize, int pageIndex, Expression<Func<Sites, bool>> funcWhere,
            string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            IQueryable<Sites> result = _context.Set<Sites>().Include(x => x.SiteDomains).Where(funcWhere);//条件筛选
            result = LinqExtensions.OrderByBatch<Sites>(result, orderBy);//调用Linq扩展类排序
            return await PaginationList<Sites>.CreateAsync(pageIndex, pageSize, result);
        }

        /// <summary>
        /// 根据IDS获取站点列表(带域名)
        /// </summary>
        public async Task<IEnumerable<Sites>> QueryListAsync(IEnumerable<int> ids, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            var result = _context.Set<Sites>().Include(x => x.SiteDomains).Where(t => ids.Contains(t.Id));
            return await result.ToListAsync();
        }

        /// <summary>
        /// 获取站点总数量
        /// </summary>
        public async Task<int> QueryCountAsync(Expression<Func<Sites, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            return await _context.Set<Sites>().Where(funcWhere).CountAsync();
        }

        /// <summary>
        /// 添加站点(含菜单创建)
        /// </summary>
        public async Task<SitesDto> AddAsync(SitesEditDto modelDto, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            //检查站点名称是否重复
            if (await _context.Set<Sites>().FirstOrDefaultAsync(x => x.Name.ToLower() == modelDto.Name.ToLower()) != null)
            {
                throw new ResponseException($"站点名称{modelDto.Name}已存在", ErrorCode.RepeatField);
            }
            //检查源数据站点是否存在
            if (modelDto.ParentId > 0 && await _context.Set<Sites>().FirstOrDefaultAsync(x => x.Id == modelDto.ParentId) == null)
            {
                throw new ResponseException($"源数据站不存在或已删除", ErrorCode.NotFound);
            }

            //映射成实体
            var model = _mapper.Map<Sites>(modelDto);
            model.AddBy = await _userService.GetUserNameAsync();
            model.AddTime = DateTime.Now;

            //开启事务
            using (var transaction = await _context.Database.BeginTransactionAsync())
            {
                try
                {
                    //添加站点
                    await _context.Set<Sites>().AddAsync(model);
                    await this.SaveAsync();
                    //如果是源数据站则添加菜单
                    if (model.ParentId == 0)
                    {
                        Navigation navModel = new Navigation
                        {
                            ParentId = 1,
                            ChannelId = 0,
                            Name = "site_" + model.DirPath,
                            Title = model.Title,
                            IsSystem = 1,
                            Controller = "Site",
                            Resource = "Show",
                            AddBy = model.AddBy,
                            AddTime = DateTime.Now
                        };
                        await _context.Set<Navigation>().AddAsync(navModel);
                        await this.SaveAsync();
                    }
                    //提交事务
                    await transaction.CommitAsync();
                }
                catch(Exception ex)
                {
                    //回滚事务
                    await transaction.RollbackAsync();
                    throw new ResponseException("保存时发生意外错误");
                }
            }
            //映射成DTO
            return _mapper.Map<SitesDto>(model);
        }

        /// <summary>
        /// 修改站点(含菜单修改)
        /// </summary>
        public async Task<bool> UpdateAsync(int id, SitesEditDto modelDto, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            //检查数据是否存在
            var model = await _context.Set<Sites>().Include(x => x.SiteDomains).FirstOrDefaultAsync(x => x.Id == id);
            if (model == null)
            {
                throw new ResponseException($"数据不存在或已删除", ErrorCode.NotFound);
            }
            //检查站点名称是否变更
            if (!modelDto.Name.Equals(model.Name)
                && await _context.Set<Sites>().FirstOrDefaultAsync(x => x.Name.ToLower() == modelDto.Name.ToLower()) != null)
            {
                throw new ResponseException($"站点名称{modelDto.Name}已存在", ErrorCode.RepeatField);
            }

            //对比模板目录是否发生改变，是则更改导航菜单名称
            if (modelDto.DirPath != model.DirPath || modelDto.Title != model.Title)
            {
                Navigation navModel = await _context.Set<Navigation>().FirstOrDefaultAsync(x => x.Name == "site_" + model.DirPath);
                navModel.Name = "site_" + modelDto.DirPath;
                navModel.Title = modelDto.Title;
                _context.Set<Navigation>().Update(navModel);
            }
            //将DTO映射到源数据,修改站点信息
            _mapper.Map(modelDto, model);
            _context.Set<Sites>().Update(model);
            //保存到数据库
            return await this.SaveAsync();
        }

        /// <summary>
        /// 删除站点(含菜单删除)
        /// </summary>
        public async Task<bool> DeleteAsync(Expression<Func<Sites, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            var list = await _context.Set<Sites>()
                .Include(x => x.SiteDomains).Where(funcWhere).ToListAsync();
            if (list == null)
            {
                return false;
            }
            foreach (var modelt in list)
            {
                //删除菜单
                var navModel = await _context.Set<Navigation>().FirstOrDefaultAsync(x => x.Name == "site_" + modelt.DirPath);
                if (navModel != null)
                {
                    _context.Set<Navigation>().Remove(navModel);
                }
                //加入追踪列表
                _context.Set<Sites>().Attach(modelt);
            }
            //删除站点
            _context.Set<Sites>().RemoveRange(list);
            //一次保存到数据库
            return await this.SaveAsync();
        }
    }
}
